// Copyright 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Jeff Stewart
// Implements the registry API over Windows Vista's externalized XML
// representation.

#include <QtCore/QFile>
#include <QtXML/QDomDocument>
#include "config/xmlregistrykey.h"

namespace popdiag {

XmlRegistryKey::XmlRegistryKey(const QString &path)
    : RegistryKey(), path_(path), node_() {
  Refresh();
}

XmlRegistryKey::~XmlRegistryKey() {
}

bool XmlRegistryKey::GetChildKeyNames(QList<QString> *out) const {
  // These XML files are leaf nodes in the registry.  There are no children.
  out->clear();
  return true;
}

RegistryKey *XmlRegistryKey::ChildKey(const QString &sub_key_name) const {
  // These XML files are leaf nodes in the registry.  There are no children.
  return NULL;
}

bool XmlRegistryKey::GetRelevantNode(const QString &value_name,
				     const char *required_type,
				     QDomNode *out) const {
  QDomNode node = GetNamedChild(value_name);
  if (required_type != GetNodeType(node)) {
    return false;
  }
  bool isElement = node.isElement();
  if (!isElement) {
    return false;
  }
  *out = node;
  return true;
}

bool XmlRegistryKey::ReadIntEntry(const QString &value_name, int *out) const {
  QDomNode node;
  if (!GetRelevantNode(value_name, "DWORD", &node)) {
    return false;
  }
  // DWORD entries in XML output files are hex encoded.
  QString hex = node.toElement().text();
  bool conversion_ok = false;
  *out = hex.toInt(&conversion_ok, 16);
  return conversion_ok;
}

bool XmlRegistryKey::ReadStringEntry(const QString &value_name,
                                     QString *out) const {
  QDomNode node;
  if (!GetRelevantNode(value_name, "SZ", &node)) {
    return false;
  }
  *out = node.toElement().text();
  return true;
}

RegistryKey *XmlRegistryKey::Copy() const {
  XmlRegistryKey *rval = new XmlRegistryKey(path_);
  return rval;
}

QString XmlRegistryKey::Dump() const {
  CHECK(false);
  return "Not implemented";
}

void XmlRegistryKey::Refresh() {
  QFile file(path_);
  if (!file.open(QIODevice::ReadOnly)) {
    return;
  }
  QDomDocument doc;
  bool process_namespaces = false;
  QString error_message;
  int error_line = 0;
  int error_col = 0;
  if (doc.setContent(file.readAll(), process_namespaces, &error_message,
                     &error_line, &error_col)) {
    node_.reset(new QDomNode(doc));
  }
  file.close();
}

QString XmlRegistryKey::GetNodeType(const QDomNode &node) const {
  if (!node.attributes().contains("type")) {
    return false;
  }
  return node.attributes().namedItem("type").nodeValue();
}

QDomNode XmlRegistryKey::GetNamedChild(const QString &value_name) const {
  QString key(value_name);
  // What would have been space delimited in the registry
  // is underbar delimited in these XML files.
  key.replace(" ", "_");
  return node_->namedItem("MessageAccount").namedItem(key);
}

bool XmlRegistryKey::ReadBinaryString(const QString &name,
                                      QString *out) const {
  // No binary strings are stored in the xml form.  Fall back to strings.
  return ReadStringEntry(name, out);
}

unsigned char *XmlRegistryKey::ReadBinaryEntry(const QString &,
                                               size_t *) const {
  CHECK(false);
  return NULL;
}

}  // namespace popdiag
